<?php

基于 bootstrap-0-入口.php

'Illuminate\Foundation\Bootstrap\LoadConfiguration' 的功能就是加载配置文件。

就是加载 \config 目录下的那些配置文件。

    public function bootstrap(Application $app)
    {
        $items = [];

        // $app->getCachedConfigPath() 就是 ...\bootstrap\cache\config.php;

        // First we will see if we have a cache configuration file. If we do, we'll load
        // the configuration items from that file so that it is very quick. Otherwise
        // we will need to spin through every configuration file and load them all.
        if (file_exists($cached = $app->getCachedConfigPath())) {
            $items = require $cached;

            $loadedFromCache = true;
        }

        $app->instance('config', $config = new Repository($items));

        // Next we will spin through all of the configuration files in the configuration
        // directory and load each one into the repository. This will make all of the
        // options available to the developer for use in various parts of this app.
        if (! isset($loadedFromCache)) {
            $this->loadConfigurationFiles($app, $config);
        }

        $app->detectEnvironment(function () use ($config) {
            return $config->get('app.env', 'production');
        });

        date_default_timezone_set($config['app.timezone']);

        mb_internal_encoding('UTF-8');
    }

    protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
    {
        foreach ($this->getConfigurationFiles($app) as $key => $path) {
            $repository->set($key, require $path);
        }
    }
    protected function getConfigurationFiles(Application $app)
    {
        $files = [];

        $configPath = realpath($app->configPath());

        foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
            $nesting = $this->getConfigurationNesting($file, $configPath);

            $files[$nesting.basename($file->getRealPath(), '.php')] = $file->getRealPath();
        }

        return $files;
    }
其中，return $files 就是
Array
(
    [app] => D:\project\study\study-php-laravel\laravel5331\config\app.php
    [auth] => D:\project\study\study-php-laravel\laravel5331\config\auth.php
    [broadcasting] => D:\project\study\study-php-laravel\laravel5331\config\broadcasting.php
    [cache] => D:\project\study\study-php-laravel\laravel5331\config\cache.php
    [compile] => D:\project\study\study-php-laravel\laravel5331\config\compile.php
    [database] => D:\project\study\study-php-laravel\laravel5331\config\database.php
    [filesystems] => D:\project\study\study-php-laravel\laravel5331\config\filesystems.php
    [mail] => D:\project\study\study-php-laravel\laravel5331\config\mail.php
    [queue] => D:\project\study\study-php-laravel\laravel5331\config\queue.php
    [services] => D:\project\study\study-php-laravel\laravel5331\config\services.php
    [session] => D:\project\study\study-php-laravel\laravel5331\config\session.php
    [view] => D:\project\study\study-php-laravel\laravel5331\config\view.php
)
全是 \config 目录下的文件。

那么，通过 $repository->set($key, require $path); 就得到了
文件名前部分为 key、文件内容为 value 的键值对。

而 RepositoryContract $repository 就是 use Illuminate\Contracts\Config\Repository as RepositoryContract;
这是一个接口，发现实现类是 \vendor\laravel\framework\src\Illuminate\Config\Repository.php
次类中有方法
    public function get($key, $default = null)
    {
        return Arr::get($this->items, $key, $default);
    }
分析 Arr::get 方法，发现重点是：
        foreach (explode('.', $key) as $segment) {
            if (static::accessible($array) && static::exists($array, $segment)) {
                $array = $array[$segment];
            } else {
                return value($default);
            }
        }
    假如 get('app.mode')，那么就是把 app.mode 拆分为 ['app', 'mode'];
    循环第一次，$segment 是 app，就是从 $this->items 中找 key 为 app 的 value，显然是一个数组；
        那么 $array 就是这个数组了，也就是 \config\app.php 文件内的那个数组；
    循环第二次，$segment 就是 mode，从 $array 找 key 为 mode 的 value，也就是 \config\app.php 中的值。
        循环结束，返回这个 value。
    当然，如果只是 get('app')，那么循环就是一次，返回的就是一个数组了，也就是说整个文件的内容。

// ==========================================================

对于 .env 中的 APP_ENV 项。
在上面的 bootstrap 方法中看到有
        $app->detectEnvironment(function () use ($config) {
            return $config->get('app.env', 'production');
        });

\vendor\laravel\framework\src\Illuminate\Foundation\Application.php
    public function detectEnvironment(Closure $callback)
    {
        $args = isset($_SERVER['argv']) ? $_SERVER['argv'] : null;

        return $this['env'] = (new EnvironmentDetector())->detect($callback, $args);
    }

\vendor\laravel\framework\src\Illuminate\Foundation\EnvironmentDetector.php
    public function detect(Closure $callback, $consoleArgs = null)
    {
        if ($consoleArgs) {
            return $this->detectConsoleEnvironment($callback, $consoleArgs);
        }

        return $this->detectWebEnvironment($callback);// web 环境下当然是执行这里；
    }
    protected function detectWebEnvironment(Closure $callback)
    {
        return call_user_func($callback);// 指示简单的执行回调而已，也就是执行
        // function () use ($config) {
        //     return $config->get('app.env', 'production');
        // }
    }
很明显，就是找 app.env，而 \config\app.php 中：
    'env' => env('APP_ENV', 'production'),

所以，$app['env'] 就是 .env 中 APP_ENV 的值。

另外，这个东西和是否显示异常、错误信息也有关系。
    protected $bootstrappers = [
        'Illuminate\Foundation\Bootstrap\DetectEnvironment',
        'Illuminate\Foundation\Bootstrap\LoadConfiguration',
        'Illuminate\Foundation\Bootstrap\ConfigureLogging',
        'Illuminate\Foundation\Bootstrap\HandleExceptions',// 这里；
        'Illuminate\Foundation\Bootstrap\RegisterFacades',
        'Illuminate\Foundation\Bootstrap\RegisterProviders',
        'Illuminate\Foundation\Bootstrap\BootProviders',
    ];

\vendor\laravel\framework\src\Illuminate\Foundation\Bootstrap\HandleExceptions.php
    public function bootstrap(Application $app)
    {
        $this->app = $app;

        error_reporting(-1);

        set_error_handler([$this, 'handleError']);

        set_exception_handler([$this, 'handleException']);

        register_shutdown_function([$this, 'handleShutdown']);

        if (! $app->environment('testing')) {
            ini_set('display_errors', 'Off');
        }
    }


\vendor\laravel\framework\src\Illuminate\Foundation\Application.php
    public function environment()
    {
        if (func_num_args() > 0) {
            $patterns = is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args();

            foreach ($patterns as $pattern) {
                if (Str::is($pattern, $this['env'])) {
                    return true;
                }
            }

            return false;
        }

        return $this['env'];
    }

\vendor\laravel\framework\src\Illuminate\Support\Str.php
    public static function is($pattern, $value)
    {
        if ($pattern == $value) {
            return true;
        }

        $pattern = preg_quote($pattern, '#');

        // Asterisks are translated into zero-or-more regular expression wildcards
        // to make it convenient to check if the strings starts with the given
        // pattern such as "library/*", making any string check convenient.
        $pattern = str_replace('\*', '.*', $pattern);

        return (bool) preg_match('#^'.$pattern.'\z#u', $value);
    }

这样一套逻辑走下来，如果 $app['env'] == 'testing'，就会显示错误信息。
如果不相等，就会执行 ini_set('display_errors', 'Off'); 不显示了。

